unit autotilehelper;
{< Parts of this modules are adapted from rpg_core/Tilemap.js from corescript,
MIT-licensed. }

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils;

function IsVisibleTile(TileId: Integer): Boolean; inline;
function IsAutotile(TileId: Integer): Boolean; inline;
function GetAutotileKind(TileId: Integer): Integer; inline;
function GetAutotileShape(TileId: Integer): Integer; inline;
function MakeAutotileId(Kind, Shape: Integer): Integer; inline;
function IsSameKindTile(TileId1, TileId2: Integer): Boolean; inline;
function IsTileA1(TileId: Integer): Boolean; inline;
function IsTileA2(TileId: Integer): Boolean; inline;
function IsTileA3(TileId: Integer): Boolean; inline;
function IsTileA4(TileId: Integer): Boolean; inline;
function IsTileA5(TileId: Integer): Boolean; inline;
function IsWaterTile(TileId: Integer): Boolean; inline;
function IsWaterBodyTile(TileId: Integer): Boolean; inline;
function IsWaterfallTile(TileId: Integer): Boolean; inline;
function IsGroundTile(TileId: Integer): Boolean; inline;
function IsShadowingTile(TileId: Integer): Boolean; inline;
function IsRoofTile(TileId: Integer): Boolean; inline;
function IsWallTopTile(TileId: Integer): Boolean; inline;
function IsWallSideTile(TileId: Integer): Boolean; inline;
function IsWallTile(TileId: Integer): Boolean; inline;
function IsFloorTypeAutotile(TileId: Integer): Boolean; inline;
function IsWallTypeAutotile(TileId: Integer): Boolean; inline;
function IsWaterfallTypeAutotile(TileId: Integer): Boolean; inline;
function GetDefaultTileFlags(TileId: Integer): Dword; inline;

implementation

uses
  constants;

function IsVisibleTile(TileId: Integer): Boolean; inline;
begin
  IsVisibleTile := (TileId > 0) and (TileId < TILE_ID_MAX);
end;

function IsAutotile(TileId: Integer): Boolean; inline;
begin
  IsAutotile := tileId >= TILE_ID_A1;
end;

function GetAutotileKind(TileId: Integer): Integer; inline;
begin
  GetAutotileKind := ((TileId - TILE_ID_A1) div 48);
end;

function GetAutotileShape(TileId: Integer): Integer; inline;
begin
  GetAutotileShape := ((TileId - TILE_ID_A1) mod 48);
end;

function MakeAutotileId(Kind, Shape: Integer): Integer; inline;
begin
  MakeAutotileId := TILE_ID_A1 + Kind * 48 + Shape;
end;

function IsSameKindTile(TileId1, TileId2: Integer): Boolean;
begin
  if IsAutotile(TileId1) and IsAutotile(TileId2) then
    IsSameKindTile := GetAutotileKind(TileId1) = GetAutotileKind(TileId2)
  else
    IsSameKindTile := TileId1 = TileId2;
end;

function IsTileA1(TileId: Integer): Boolean; inline;
begin
  IsTileA1 := (TileId >= TILE_ID_A1) and (TileId < TILE_ID_A2);
end;

function IsTileA2(TileId: Integer): Boolean; inline;
begin
  IsTileA2 := (TileId >= TILE_ID_A2) and (TileId < TILE_ID_A3);
end;

function IsTileA3(TileId: Integer): Boolean; inline;
begin
  IsTileA3 := (TileId >= TILE_ID_A3) and (TileId < TILE_ID_A4);
end;

function IsTileA4(TileId: Integer): Boolean; inline;
begin
  IsTileA4 := (TileId >= TILE_ID_A4) and (TileId < TILE_ID_MAX);
end;

function IsTileA5(TileId: Integer): Boolean; inline;
begin
  IsTileA5 := (TileId >= TILE_ID_A5) and (TileId < TILE_ID_A1);
end;

function IsWaterTile(TileId: Integer): Boolean; inline;
begin
  if IsTileA1(TileId) then
    IsWaterTile := not ((TileId >= TILE_ID_A1 + 96) and (TileId < TILE_ID_A1 + 192))
  else
    IsWaterTile := False
end;

function IsWaterBodyTile(TileId: Integer): Boolean;
var
  Kind: Integer;
begin
  if IsTileA1(TileId) then begin
    Kind := GetAutotileKind(TileId);
    IsWaterBodyTile := (Kind = 0) or ((Kind mod 2 = 0) and (Kind > 3));
  end else
    IsWaterBodyTile := False;
end;

function IsWaterfallTile(TileId: Integer): Boolean; inline;
begin
  if (TileId >= TILE_ID_A1 + 192) and (TileId < TILE_ID_A2) then
    IsWaterfallTile := GetAutotileKind(TileId) mod 2 = 1
  else
    IsWaterfallTile := False;
end;

function IsGroundTile(TileId: Integer): Boolean; inline;
begin
  IsGroundTile := IsTileA1(TileId) or IsTileA2(TileId) or isTileA5(TileId);
end;

function IsShadowingTile(TileId: Integer): Boolean; inline;
begin
  IsShadowingTile := IsTileA3(TileId) or IsTileA4(TileId);
end;

function IsRoofTile(TileId: Integer): Boolean; inline;
begin
  IsRoofTile := IsTileA3(TileId) and (GetAutotileKind(TileId) mod 16 < 8);
end;


function IsWallTopTile(TileId: Integer): Boolean; inline;
begin
  IsWallTopTile := IsTileA4(TileId) and (GetAutotileKind(TileId) mod 16 < 8);
end;

function IsWallSideTile(TileId: Integer): Boolean; inline;
begin
  IsWallSideTile := (IsTileA3(TileId) or IsTileA4(TileId)) and
          (GetAutotileKind(TileId) mod 16 >= 8);
end;

function IsWallTile(TileId: Integer): Boolean; inline;
begin
  IsWallTile := IsWallTopTile(TileId) or IsWallSideTile(TileId);
end;

function IsFloorTypeAutotile(TileId: Integer): Boolean; inline;
begin
  IsFloorTypeAutotile := (IsTileA1(TileId) and not IsWaterfallTile(TileId))
                         or IsTileA2(TileId) or IsWallTopTile(TileId)
end;

function IsWallTypeAutotile(TileId: Integer): Boolean; inline;
begin
  IsWallTypeAutotile := IsRoofTile(TileId) or IsWallSideTile(TileId);
end;

function IsWaterfallTypeAutotile(TileId: Integer): Boolean; inline;
begin
  IsWaterfallTypeAutotile := IsWaterfallTile(TileId)
end;

function GetDefaultTileFlags(TileId: Integer): Dword;
var
  K: Integer;
begin
  if TileId = 0 then
    Result := 16
  else if IsAutotile(TileId) then begin
    K := GetAutotileKind(TileId);
    if (K = 1) then
      Result := 512 //dark water, impassable for boat
    else if (K <> 0) and not (IsTileA1(TileId) and (K > 3) and not Odd(K)) then
      Result := 512 or 1024; //water, impassable for ship

    if IsTileA1(TileId) or (IsTileA2(TileId) and ((K mod 8) <= 3))
                         or IsTileA3(TileId) or IsTileA4(TileId) then
        Result := Result or 2048;
  end;
end;

end.

